<?php
/**
 * Created by paperphp
 * User: 22071
 * Date: 2019/9/3
 * Email: <zhendongdong@foxmail.com>
 */

namespace paper\pdo;


use paper\exception\DbException;
use PDO;
use PDOException;
use PDOStatement;

class Mysql
{
    /**
     * Db constructor.
     * @param $config
     * @param null $table
     * @param null $prefix
     */
    private $pdo = null;
    private $callback = null;

    public function __construct($hostname, $port, $database, $charset, $username = "", $password = "")
    {
        $dsn       = 'mysql:host=' . $hostname . ';port=' . $port . ';dbname=' .
            $database . ';charset=' . $charset;
        $this->pdo = new PDO($dsn, $username, $password);
        $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }

    public function beforePrepare(\Closure $closure)
    {
        $this->callback = $closure;
    }

    /**
     * @return PDO|null
     */
    public function pdo()
    {
        return $this->pdo;
    }

    /**
     * @param $sql
     * @return bool|PDOStatement
     */
    public function prepare($sql)
    {
        if ($this->callback) {
            $callback = $this->callback;
            /** @var callable $callback */
            $callback($sql);
        }
        try {
            $statement = $this->pdo->prepare($sql);
            $statement->setFetchMode(PDO::FETCH_ASSOC);
            return $statement;
        } catch (PDOException $exception) {
            $dbException = new DbException($exception->getMessage());
            $dbException->setSql($sql);
            throw  $dbException;
        }
    }

    /**
     * @param PDOStatement $statement
     * @param array $data
     * @return bool|int
     */
    public function execute(PDOStatement $statement, $data = [])
    {
        if (!$result = $statement->execute($data)) {
            return false;
        }
        return $statement->rowCount() ?: false;
    }

    public function select(PDOStatement $statement, $data = [])
    {
        if (!$result = $statement->execute($data)) {
            return false;
        }
        $result_arr = $statement->fetchAll();
        return $result_arr ?: false;
    }

    /**
     * @param PDOStatement $statement
     * @param array $data
     * @return bool|array
     */
    public function find(PDOStatement $statement, $data = [])
    {
        if (!$result = $statement->execute($data)) {
            return false;
        }
        $result_arr = $statement->fetch();
        return $result_arr ?: false;
    }
}